fix(dynamic-agents): correlate subagent namespaces across langgraph tasks-chunk shapes#1683
Merged
subbaksh merged 1 commit intoJun 4, 2026
Conversation
…asks-chunk shapes
[GAI]
The AG-UI stream encoder builds a {namespace -> tool_call_id} mapping from
`tasks`-mode stream metadata so subagent events can be attributed to the
`task` tool call that spawned them. Clients rely on this attribution
(NAMESPACE_CONTEXT events) to distinguish subagent output from the parent
agent's response.
langgraph changed the shape of the `tasks`-mode `input` field between
versions:
- < 1.2: input is a dict {"__type": "tool_call_with_context",
"tool_call": {...}, "state": {...}}
- >= 1.2: input is a bare list of tool_call dicts
`_handle_tasks_chunk` only parsed the dict shape (input.tool_call), so on
langgraph >= 1.2 the mapping stayed empty. With no mapping, every subagent
namespace fell through `correlate_namespace`'s 'unknown -> treat as parent'
path, no NAMESPACE_CONTEXT events were emitted, and subagent narration leaked
into the parent agent's final response.
Parse both shapes via a new `_extract_task_tool_calls` helper and iterate
the resulting tool_calls. Add regression tests covering both chunk shapes,
end-to-end correlation, the uncorrelated fallback, and non-task tool calls.
Signed-off-by: Erik Lutz <elutz@splunk.com>
Prebuild Artifacts for
|
| Artifact | Image | Tag | Status | CI |
|---|---|---|---|---|
| caipe-dynamic-agents | ghcr.io/cnoe-io/prebuild/caipe-dynamic-agents |
fix-subagent-namespace-correlation-2 |
Published | CI |
Docker pull commands
docker pull ghcr.io/cnoe-io/prebuild/caipe-dynamic-agents:fix-subagent-namespace-correlation-2These prebuild artifacts will be automatically cleaned up when the PR is closed or merged.
93652c4
into
prebuild/hotfix-cnoe-agent-utils-anthropic-bedrock
10 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a regression where subagent narration leaks into the parent agent's
final response (e.g. a streamed answer that begins with "I'll look up the
weather...", "I'll search for...", "Now let me..." before the real answer).
The leak appears after upgrading langgraph to >= 1.2 and is not caused
by the LLM client choice (
ChatBedrockConversevsChatAnthropicBedrock) —both stream identically. The trigger is a change in the shape of langgraph's
tasks-mode stream metadata that silently broke subagent namespacecorrelation in the AG-UI encoder.
Root cause
AGUIStreamEncoder(viaLangGraphStreamHelper._handle_tasks_chunk) builds a{namespace -> tool_call_id}mapping fromtasks-mode chunks so that subagentevents can be attributed to the
tasktool call that spawned them. Clients usethis attribution (emitted as
NAMESPACE_CONTEXTevents) to tell subagent outputapart from the parent agent's own response.
langgraph changed the shape of the
taskschunkinputfield between versions:_handle_tasks_chunkonly read the dict shape (input.get("tool_call")). Onlanggraph >= 1.2,
inputis a list, so the lookup returned{}, the mappingstayed empty, and
correlate_namespacetook its fallback branch:Every subagent namespace was therefore classified as the parent. As a result:
NAMESPACE_CONTEXTevents were emitted (the namespace never "changed"from the parent's empty tuple).
on, so subagent narration was rendered as the parent's answer.
This also produced a flood of
[sse:correlate] Unknown namespace ...warningsin the logs, which is the visible fingerprint of the bug.
Fix
Parse both
inputshapes via a new_extract_task_tool_callshelper anditerate the resulting tool calls. The dict (
tool_call_with_context) and listforms both normalize to a list of tool-call dicts, so the mapping populates
correctly regardless of langgraph version. No protocol or consumer changes are
required — restoring the mapping makes the existing
NAMESPACE_CONTEXTattribution work again for all clients.
How it was verified
Reproduced end-to-end against a parent agent invoking parallel subagents,
streaming through the real
AGUIStreamEncoder, comparing langgraph 1.0.x vs1.2.x:
NAMESPACE_CONTEXTeventsTests
Adds
TestTasksChunkNamespaceMappingcovering:tasktool calls are ignoredAll encoder/namespace tests pass;
ruffclean.Type of Change